package org.benjamin.lending.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.benjamin.lending.domain.WithdrawCost;
import org.benjamin.lending.domain.entity.MemberInfo;
import org.benjamin.lending.domain.entity.RechargeLog;
import org.benjamin.lending.domain.entity.TransactRequest;
import org.benjamin.lending.domain.entity.TransactRequest.Status;
import org.benjamin.lending.domain.entity.TransactRequest.Type;
import org.benjamin.lending.domain.entity.TransactType;
import org.benjamin.lending.domain.entity.WithdrawalsLog;
import org.benjamin.lending.domain.form.RealNameForm;
import org.benjamin.lending.domain.form.RechargeForm;
import org.benjamin.lending.domain.form.Subledger;
import org.benjamin.lending.domain.form.WithdrawForm;
import org.benjamin.lending.domain.transact.BasicOutBean;
import org.benjamin.lending.domain.transact.TransactBean;
import org.benjamin.lending.repository.MemberInfoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.fasterxml.jackson.databind.ObjectMapper;

@Transactional
@Service("sumapayTransactService")
public class SumapayTransactServiceImpl extends DefaultTransactServiceImpl{
	
	private Logger logger = LogManager.getLogger();
	
	@Value("${sumapay.merchantCode}")
	private String merchantCode;
	
	@Value("${sumapay.secretKey}")
	private String securityKey;
	
	private static final boolean REAL_NAME_SYNC = true;
	
	
	@Autowired
	private MemberInfoRepository memberInfoRepository;
	
	private static final String TARGET_URL_DONAME = "http://localhost:8080/lending-web/sumapayTest";
	
	public static final String REAL_NAME_URL = TARGET_URL_DONAME+"/main/UserForFT_realNameAuth";
	
	public static final String[] REQUEST_BASIC = {"requestId","merchantCode"};
	public static final String[] REQUEST_REGISTER_USER = ArrayUtils.addAll(REQUEST_BASIC, "userIdIdentity","successReturnUrl","failReturnUrl","payType");
	/**
	 * 请求充值签名规则
	 */
	public static final String[] REQUEST_USER_RECHARGE = ArrayUtils.addAll(REQUEST_BASIC, "userIdIdentity","sum","bankCode","successReturnUrl","failReturnUrl","bankcardTypeFlag","payType","subledgerList");
	public static final String[] REQUEST_REAL_NAME = ArrayUtils.addAll(REQUEST_BASIC, "userName","idNumber","payType","noticeUrl","merBizRequestId");
	/**
	 * 请求提现签名规则
	 */
	public static final String[] REQUEST_WITHDRAW = ArrayUtils.addAll(REQUEST_BASIC, "userIdIdentity","sum","successReturnUrl","failReturnUrl","payType","subledgerList");
	
	public static final String[] RESPONSE_BASIC = {"requestId","result"};
	public static final String[] RESPONSE_REGISTER_USER = ArrayUtils.addAll(RESPONSE_BASIC, "userIdIdentity","userId");
	public static final String[] RESPONES_USER_RECHARGE = ArrayUtils.addAll(RESPONSE_BASIC, "sum","userIdIdentity","userBalance");
	public static final String[] RESPONSE_REAL_NAME = ArrayUtils.addAll(RESPONSE_BASIC, "userName","status","token","idNumber");
	//响应提现签名规则
	public static final String[] RESPONSE_WITHDRAW = ArrayUtils.addAll(RESPONSE_BASIC, "sum","userIdIdentity","userBalance");
	
	
	@Override
	public BasicOutBean realNameRequest(String username,RealNameForm realNameForm) {
		//检查当前表单是否重复提交过
		super.realNameRequest(username,realNameForm);
		MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
		BasicOutBean basicOutBean = new BasicOutBean();
		basicOutBean.setMemberInfo(memberInfo);
		basicOutBean.setOrigParam(realNameForm);
		Map<String,Object> paramterMap = new HashMap<String, Object>();
		paramterMap.put("userName", realNameForm.getUserName());
		paramterMap.put("idNumber", realNameForm.getIdNumber());
		paramterMap.put("payType", 1);
		TransactBean transactBean = new TransactBean();
		transactBean.setParamterMap(paramterMap);
		transactBean.setTargetUrl(REAL_NAME_URL);
		basicOutBean.setTransactBean(transactBean);
		basicOutBean.setSync(true);
		basicOutBean.setMq(true);
		basicOutBean.setQueueName("realNameTransactRequest");
		basicOutBean.setSignatureNames(REQUEST_REAL_NAME);
		basicOutBean.getTransactRequest().setType(Type.REAL_NAME);
		return basicOutBean;
	}
	
	public TransactRequest realNameResponse(Map<String,Object> responseMap) {
		String requestId = responseMap.get("requestId").toString();
		if(!checkTheSignature(responseMap, RESPONSE_REAL_NAME)) {
			throw new IllegalArgumentException("签名出现异常，无法确认参数的正确性");
		}
		TransactRequest basicOutBean = super.realNameResponse(responseMap, requestId);
		try {
			String resultData = new ObjectMapper().writeValueAsString(responseMap);
			basicOutBean.setResultData(resultData);
		}catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		return basicOutBean;
	}
	
	@Override
	public BasicOutBean registerAccessRequest(String username) {
		BasicOutBean basicOutBean = super.registerAccessRequest(username);
		TransactBean transactBean = new TransactBean();
		transactBean.setTargetUrl(TARGET_URL_DONAME+"/user/register_toRegister");
		logger.info("查询用户[{}],是否存在",username);
		MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
		Assert.notNull(memberInfo,"当前用户不存在");
		Map<String,Object> paramterMap = new HashMap<String, Object>();
		String userIdIdentity = this.getUserIdIdentity(username);
		paramterMap.put("userIdIdentity", userIdIdentity);
		if(StringUtils.isNotBlank(memberInfo.getMobile())) {
			paramterMap.put("telephone", memberInfo.getMobile());
		}
		if(StringUtils.isNotBlank(memberInfo.getRealName())) {
			paramterMap.put("name", memberInfo.getRealName());
		}
		if(StringUtils.isNotBlank(memberInfo.getIdNumber())) {
			paramterMap.put("idNumber", memberInfo.getIdNumber());
			paramterMap.put("idType", 1);
		}
		paramterMap.put("payType", 0);
		transactBean.setParamterMap(paramterMap);
		basicOutBean.setTransactBean(transactBean);
		basicOutBean.setSignatureNames(this.REQUEST_REGISTER_USER);
		
		//
		basicOutBean.getTransactRequest().setMemberInfo(memberInfo);
		basicOutBean.getTransactRequest().setType(Type.REGISTER_USER);
		return basicOutBean;
	}

	@Override
	public TransactRequest registerAccountResponse(TransactRequest transactRequest, Map<String, Object> responseMap) {
		if(responseMap.get("result").equals("00000")){
			logger.debug("用户开通账户成功");
			//super.registerAccountResponse(transactRequest,responseMap);
			MemberInfo memberInfo = transactRequest.getMemberInfo();
			if(StringUtils.isBlank(memberInfo.getRealName())){
				memberInfo.setRealName(responseMap.get("name").toString());
			}
			if(StringUtils.isBlank(memberInfo.getMobile())){
				memberInfo.setMobile(responseMap.get("telephone").toString());
			}
			transactRequest.setStatus(Status.COMPLETE);
			//this.memberInfoRepository.save(memberInfo);
		}else{
			logger.debug("开通账户失败");
			transactRequest.setStatus(Status.FAIL);
		}
		return transactRequest;
	}

	@Override
	public BasicOutBean userRechargeRequest(RechargeForm rechargeForm, String username) {
		BasicOutBean basicOutBean = super.userRechargeRequest(rechargeForm, username);
		basicOutBean.setOrigParam(rechargeForm);
		logger.info("开始封装数据");
		TransactBean transactBean = new TransactBean();
		transactBean.setTargetUrl(TARGET_URL_DONAME+"/user/webBankRecharge_toRecharge");
		basicOutBean.setSignatureNames(REQUEST_USER_RECHARGE);
		Map<String,Object> paramterMap = new HashMap<String, Object>();
		String userIdIdentity = this.getUserIdIdentity(username);
		paramterMap.put("userIdIdentity", userIdIdentity);
		paramterMap.put("sum", rechargeForm.getAmount());
		paramterMap.put("bankCode", rechargeForm.getBankID());
		paramterMap.put("bankcardTypeFlag", 0);
		paramterMap.put("payType", 2);
		//分账列表
		List<Subledger> subledgers = new ArrayList<Subledger>();
		subledgers.add(new Subledger(0,userIdIdentity,0,rechargeForm.getAmount()));
		transactBean.setSubledger(subledgers);
		transactBean.setParamterMap(paramterMap);
		basicOutBean.setTransactBean(transactBean);
		basicOutBean.getTransactRequest().setType(Type.RECHARGE);
		basicOutBean.getTransactRequest().setMoney(rechargeForm.getAmount());
		RechargeLog rechargeLog = (RechargeLog)basicOutBean.getResultData();
		basicOutBean.getTransactRequest().setRelationId(rechargeLog.getId());
		return basicOutBean;
	}
	
	/**
	 * 用户充值相应
	 */
	@Override
	public TransactRequest userRechargeResponse(TransactRequest transactRequest,Map<String,Object> responseMap) {
		boolean finshSuccess =false;
		logger.info("充值响应请求");
		if(responseMap.get("result").equals("00000")) {
			finshSuccess = true;
			transactRequest.setStatus(Status.COMPLETE);
			logger.info("充值完成");
		}else {
			transactRequest.setStatus(Status.FAIL);
			logger.info("充值失败");
		}
		super.userRechargeResponse(transactRequest.getRelationId(), finshSuccess, responseMap);
		return transactRequest;
	}
	
	/**
	 * 用户丰付提现请求请求
	 * @param username 当前需要用户名
	 * @param withdrawFrom 提现页面表单
	 * @param serviceCharge 提现手续费
	 * @return
	 */
	@Override
	public BasicOutBean withdrawRequest(String username,WithdrawForm withdrawFrom,BigDecimal serviceCharge) {
		logger.info("提现请求封装参数");
		BasicOutBean basicOutBean = super.withdrawRequest(username,withdrawFrom,serviceCharge);
		WithdrawalsLog withdrawalsLog = (WithdrawalsLog)basicOutBean.getResultData();
		Assert.notNull(withdrawalsLog,"关联的提现记录不存在，请相关工作人员检查！");
		basicOutBean.getTransactRequest().setRelationId(withdrawalsLog.getId());
		basicOutBean.getTransactRequest().setType(Type.WITHDRAW);
		
		basicOutBean.setOrigParam(withdrawFrom);
		basicOutBean.setSignatureNames(REQUEST_WITHDRAW);
		TransactBean transactBean = new TransactBean();
		transactBean.setTargetUrl(TARGET_URL_DONAME+"/user/withdraw_toWithdraw");
		Map<String,Object> paramterMap = new HashMap<String, Object>();
		String userIdIdentity = this.getUserIdIdentity(username);
		paramterMap.put("userIdIdentity", userIdIdentity);
		paramterMap.put("sum", withdrawFrom.getAmount());
		paramterMap.put("payType", 2);
		List<Subledger> subledgers = new ArrayList<Subledger>();
		if(serviceCharge != null && serviceCharge.compareTo(BigDecimal.ZERO) == -1) {
			subledgers.add(new Subledger(0, userIdIdentity, 0, withdrawFrom.getAmount().subtract(serviceCharge)));
			subledgers.add(new Subledger(1, this.merchantCode, 1, serviceCharge));
		}else {
			subledgers.add(new Subledger(0, userIdIdentity, 0, withdrawFrom.getAmount()));	
		}
		transactBean.setSubledger(subledgers);
		transactBean.setParamterMap(paramterMap);
		basicOutBean.setTransactBean(transactBean);
		return basicOutBean;
	}
	
	@Override
	public TransactRequest withdrawResponse(TransactRequest request,Map<String,Object> responseMap) {
		if(responseMap.get("result").equals("00000")) {
			String noticeType = responseMap.get("noticeType").toString();
			if(noticeType.equals("0")) {
				logger.info("丰付请求已经受理");
				request.setStatus(Status.PROCESS);
				String bankName = null,bankCode = null;
				Object temp = responseMap.get("bankCode");
				if(temp != null) {
					bankCode = temp.toString();
				}
				temp = responseMap.get("bankName");
				if(temp != null) {
					bankName = temp.toString();
				}
				this.memberInfoService.withdrawAccept(TransactType.SUMAPAY,request.getRelationId(),bankCode,bankName);
			}else if(noticeType.equals("1")) {
				logger.info("丰付请求已经到账处理");
				request.setStatus(Status.COMPLETE);
				this.memberInfoService.withdrawReceived(TransactType.SUMAPAY,request.getRelationId());
			}else {
				throw new IllegalAccessError("出现异常无法确认丰付返回通知类型:"+noticeType)  ;
			}
			return request;
		}else {
			this.memberInfoService.withdrawFail(request.getRelationId(), responseMap.get("result").toString());
			request.setStatus(Status.FAIL);
			return request;
		}
	}
	
	public String getUserIdIdentity(String username) {
		return "lending_"+username;
	}

	@Override
	public String signature(Map<String,Object> responseMap,String... signatureKeyArray){
		StringBuffer stringBuffer = new StringBuffer();
		for(String key : signatureKeyArray) {
			Object value = responseMap.get(key);
			if(value != null) {
				stringBuffer.append(value);
			}else {
				logger.warn("当前{}键值不存在",key);
			}
		}
		String valueToDigest = stringBuffer.toString();

		String signatureCode = HmacUtils.hmacMd5Hex(this.securityKey, valueToDigest.toString());
		logger.debug("组合校验数据明码：{},校验加密后：{}。",valueToDigest,signatureCode);
		return signatureCode;
	}
	
	public boolean checkTheSignature(Map<String,Object> responseMap,String... signatureKeyArray) {
		String signatureCode = this.signature(responseMap,signatureKeyArray);
		logger.debug("校验数据和合法性");
		Assert.notNull(responseMap.get("signature"), "无法获取数字校验编码值");;
		if(responseMap.get("signature").equals(signatureCode)) {
			logger.debug("校验数据匹配成功，可进行下一步了");
			return true;
		}
		logger.error("校验数据不一致，丰付平台返回数据是：{}",responseMap);
		return false;
	}
	


}
